#include "Mage.h"
using namespace std;

const unsigned int Mage::nbr_comp = 26;

const unsigned int Mage::nbr_restric = 15;

ListComp Mage::Comp[26] = {
  {"Abjuration"                       ,  5, false},
  {"Altération"                       ,  5, false},
  {"Conjuration - Convocation"        ,  5, false},
  {"Divination"                       ,  5, false},
  {"Enchantement - Charme"            ,  5, false},
  {"Illusion - Fantasme"              ,  5, false},
  {"Invocation - Evocation"           ,  5, false},
  {"Nécromancie"                      ,  5, false},
  {"Armes de roublard / prêtre"       , 10, false},
  {"Compétences supplémetaire"        ,  0, false},
  {"Coriace"                          ,  5, false},
  {"Dés de vie à 1d6"                 , 10, false},
  {"Détection de la magie"            , 10, false},
  {"Dissipation de la magie (1x/j)"   , 10, false},
  {"Dissipation de la magie (3x/j)"   , 15, false},
  {"Durée de sorts acrue (1 école)"   , 10, false},
  {"Durée de sorts acrue"             , 15, false},
  {"Incantation rapide"               ,  5, false},
  {"Lecture de la magie"              , 10, false},
  {"Mage combattant"                  , 10, false},
  {"Mage en armure"                   , 15, false},
  {"Magicien-pêtre"                   , 15, false},
  {"Résistance aux charmes et sommeil",  5, false},
  {"Sélection d'armes étendue"        , 15, false},
  {"Sort automatique"                 ,  5, false},
  {"Spécialisation"                   , 15, false}
};

ListComp Mage::Restric[15] = {
  {"Choix des armes restreint (déf ok)",  3},
  {"Choix des armes restreint"         ,  5},
  {"Comportement / tabou"              ,  2},
  {"Condition extérieures"             ,  0},
  {"Dés de vie à 1d3"                  , 10},
  {"Difficultés de mémorisation"       ,  5},
  {"Limitation d'objets magiques"      ,  0},
  {"Manque de discrétion"              ,  5},
  {"Nombre de sorts réduit"            ,  7},
  {"Progression ralentie"              , 15},
  {"Restriction surnaturelle"          ,  0},
  {"Sorts dangereux"                   , 10},
  {"Talisman"                          ,  8},
  {"Temps d'incantation alongé (+3)"   ,  2},
  {"Temps d'incantation alongé (unité)",  5}
};

Mage::Mage(unsigned int xp, unsigned int trait[7], unsigned int PP)
  : Classe(xp, trait, Magiciens)
{
  Type_classe = "Mage";
  PP += 40;
  dout(BLANK) << setfill('*') << setw(56) << '*' << endreq;
  dout(BLANK) << "Création d'un mage" << endreq << endl;
  unsigned int nbr(0);

  for (unsigned int i(0); i<nbr_restric; i++)
    {
      if (Restric[i].Cout != 0)
	dout(BLANK) << i+1 << ' ' << Restric[i].Comp << " ("
		    << Restric[i].Cout << " pp)" << endreq;
      else
	dout(BLANK) << i+1 << ' ' << Restric[i].Comp << " cout variable"
		    << endreq;	
    }
  dout(BLANK) << nbr_restric+1 << " Aucune" << endreq;
  
  bool test(true), deja_pris, encore(false);
  unsigned int save_PP(PP);

  do
    {
      do
	{
	  nbr = demander_unsigned_borne("Choisir les restrictions ", 1,
					nbr_restric + 1);
	  if (nbr!=nbr_restric+1)
	    {
	      if (Restric[nbr-1].Cout == 0)
		{
		  deja_pris = safe_push_back(&Comp_classe, nbr_comp - 1 + nbr);
		  if (deja_pris)
		    dout(WARN) << "Déjà sélectionné" << endreq;
		  else
		    {
		      Comp_classe.push_back(nbr_comp + 1 + nbr);
		      unsigned int pps;
		      pps =  demander_unsigned("Entrez les PP obtenus : ");
		      PP += pps;
		      dout(BLANK) << "Restriction choisie : "
				  << Restric[nbr-1].Comp << endreq;
		    }
		}
	      else
		{
		  deja_pris = safe_push_back(&Comp_classe, nbr_comp - 1 + nbr);
		  if (deja_pris)
		    dout(WARN) << "Déjà sélectionné" << endreq;
		  else
		    {
		      Comp_classe.push_back(nbr_comp + 1 + nbr);
		      PP += Restric[nbr-1].Cout;
		      dout(BLANK) << "Restriction choisie : "
				  << Restric[nbr-1].Comp << endreq;
		    }
		}
	    }
	  else
	    test = false;
	}
      while(test);

      affiche_competences();
      dout(BLANK) << endl <<  "1 pour continuer, 2 pour recommencer" << endreq;
      nbr = demander_unsigned_borne("Choix ", 1, 2);
      if (nbr == 2)
	{
	  PP = save_PP;
	  Comp_classe.clear();
	  test = true;
	  encore = true;
	  dout(BLANK) << endreq;
	}
      else
	encore = false;
    }
  while(encore);

  test = true;
      
  dout(BLANK) << "Tu as " << PP << " pp à dépenser" << endreq;
  save_PP = PP;
  
  for (unsigned int i(0); i<nbr_comp; i++)
    {
      if (Comp[i].Cout != 0)
	dout(BLANK) << i+1 << ' ' << Comp[i].Comp << " (" << Comp[i] .Cout
		    << " pp)" << endreq;
      else
	dout(BLANK) << i+1 << ' ' << Comp[i].Comp << " (cout variable)"
		    << endreq;	
    }
  dout(BLANK) << nbr_comp+1 << " Aucune" << endreq;
  dout(BLANK) << "Choisir les compétences de classe" << endreq;
  
  do
    {
      do
	{
	  nbr = demander_unsigned_borne("("+write_int(PP)+" restants) ", 1,
					nbr_comp + 1);
	  if (nbr!=nbr_comp+1)
	    {
	      if (PP >= Comp[nbr-1].Cout)
		{
		  deja_pris = safe_push_back(&Comp_classe, nbr - 1);
		  if (deja_pris)
		    dout(WARN) << "Déjà sélectionné" << endreq;
		  else
		    {
		      Comp_classe.push_back(nbr-1);
		      PP -= Comp[nbr-1].Cout;
		      dout(BLANK) << "Compétence choisie : " << Comp[nbr-1].Comp
				  << endreq;
		    }
		}
	      else
		dout(BLANK) << "Pas assez de pp" << endreq;
	    }
	  else
	    test = false;
	}
      while(test);

      affiche_competences();
      dout(BLANK) << endl <<  "1 pour continuer, 2 pour recommencer" << endreq;
      nbr = demander_unsigned_borne("Choix ", 1, 2);
      if (nbr == 2)
	{
	  PP = save_PP;
	  while(Comp_classe.back() < nbr_comp)
	    Comp_classe.pop_back();
	  test = true;
	  encore = true;
	  dout(BLANK) << endreq;
	}
      else
	encore = false;
    }
  while(encore);

  dout(BLANK) << endl << setfill('*') << setw(56) << '*' << endreq;
  calcul_niveau();
}

Mage::Mage(unsigned int xp, unsigned int trait[7])
  : Classe(xp, trait, Magiciens)
{
  Type_classe = "Mage";
  calcul_niveau();
  calcul_niv_mag();
}

Mage::~Mage()
{}

void Mage::calcul_niveau()
{
  if (XP < 60000)
    {
      unsigned int i;
      for (i = 0; i < 5; i++)
	{
	  if (XP < (unsigned int) 2500 * puissance(2, i))
	    break;
	}
      Niveau = i+1;
    }
  else if (XP < 90000)
    Niveau = 7;
  else if (XP < 135000)
    Niveau = 8;
  else if (XP < 250000)
    Niveau = 9;
  else if (XP < 375000)
    Niveau = 10;
  else if (XP < 750000)
    Niveau = 11;
  else
      Niveau = (XP - 750000) / 375000 + 12;
}

void Mage::afficher_stats()
{
  dout(BLANK) << "Mage" << endreq;
  for (unsigned int i(0); i<6; i++)
    dout(BLANK) << Caracteristiques[i] << ' ' << Traits[i] << endreq;
  for (unsigned int i(0); i<Comp_classe.size(); i++)
    {
      if (Comp_classe[i] >= nbr_comp)
	{
	  dout(BLANK) << Comp_classe[i] << endreq;
	  dout(BLANK) << Restric[Comp_classe[i]-20].Comp << endreq;
	}
      else
	dout(BLANK) << Comp[Comp_classe[i]].Comp << endreq;
    }
}

void Mage::appliquer_modif(const string& type)
{}

void Mage::augmenter_talents(const unsigned int& bonus, const bool& lvl_up)
{}

void Mage::get_JS(unsigned int *tab) const
{
  *(tab + 0) = 14; // Paralysie, Poison ou Mort magique
  *(tab + 1) = 11; // Bâton, batonnet baguette
  *(tab + 2) = 13; // Pétrification ou Métamorphose
  *(tab + 3) = 15; // Souffles
  *(tab + 4) = 12; // Sorts
  
  unsigned int cat;
  if (Niveau <= 5)
    cat = 0;
  else  if (Niveau <= 10)
    cat = 1;
  else  if (Niveau <= 15)
    cat = 2;
  else  if (Niveau <= 20)
    cat = 3;
  else
    cat = 4;

  *(tab + 0) -= cat;
  *(tab + 1) -= 2 * cat;
  *(tab + 2) -= 2 * cat;
  *(tab + 3) -= 2 * cat;
  *(tab + 4) -= 2 * cat;
}

string Mage::get_competence(const unsigned int& i) const
{
  DebugLevelType etat_precedent(dout.getLevel());
  dout.setLevel(elementaire);
  dout(DEBUG) <<  i << "-ème compétence => Compétence " << get_comp(i)
	      << endreq;
  if (get_comp(i) < nbr_comp)
    {
      dout(DEBUG) << "=> compétence" << endreq;
      dout.setLevel(etat_precedent);
      return Comp[get_comp(i)].Comp;
    }
  else
    {
      dout(DEBUG) << "=> restriction" << endreq;
      dout.setLevel(etat_precedent);
      return Restric[get_comp(i)-nbr_comp].Comp;
    }
}

unsigned int Mage::calcule_TAc0() const
{
  unsigned int mod_niveau((Niveau - 1) / 3);

  return 20 - mod_niveau;
}

void Mage::calcul_niv_mag()
{
  if (Niveau < 11)
    Niveau_mag = (Niveau + 1) / 2;
  else if (Niveau == 11)
    Niveau_mag = 5;
  else if (Niveau < 20)
    Niveau_mag = Niveau / 2;
  else
    Niveau_mag = 9;
}

void Mage::ecrire_sorts(const string& nom_fichier, const bool& ecrase) const
{
  DebugLevelType etat_precedent(dout.getLevel());
  dout.setLevel(fonction);
  dout(FUNC) << "Mage::ecrire_sorts -> début" << endreq;
  ofstream sortie;
  if (ecrase)
    {
      dout(DEBUG) << "Ecrasement du fichier " << nom_fichier << endreq;
      sortie.open(nom_fichier.c_str());
    }
  else
    {
      sortie.open(nom_fichier.c_str(), ios::app);
      sortie << "\\newpage" << endl;
    }

  sortie << "\\section*{Livre de sorts - Mage}" << endl;

  unsigned int *vec = new unsigned int[Niveau_mag];

  nbr_sort(vec, Niveau_mag);
  
  sortie << "\\begin{center}" << endl 
	 << "\\begin{tabular*}{10cm}{@{\\extracolsep{\\fill}} l r}"
	 << endl << "\\multicolumn{2}{c}{Nombre de sorts par jour} \\\\"
	 << "\\hline \\\\ \\vspace{1mm}" << endl;
  for (unsigned int i(0); i < Niveau_mag; i++)
    sortie << "Niveau " << i+1 << " & " << vec[i] << " \\\\" << endl;
  sortie << "\\end{tabular*}" << endl << "\\end{center}" << endl;

  unsigned int taille(get_combien_sorts()), i, courant(10), niv_courant(10);
  string nom_ecoles[8] = {
    "Abjuration", "Alt\\'eration", "Conjuration - Convocation",
    "Divination","Enchantement - Charme", "Illusion - Fantasme",
    "Invocation - Evocation", "N\\'ecromancie"};

  dout(DEBUG) << "nbr de sorts = " << taille << endreq;

  for(i = 0; i < taille; i++)
    {
      dout(DEBUG) << "Sort courant " << Cl_sorts[i] << endreq;
      if (Cl_sorts[i].get_Ecole() != courant)
	{
	  courant = Cl_sorts[i].get_Ecole();
	  niv_courant = Cl_sorts[i].get_Niveau();
	  // courant garde en mémoire l'école courante
	  // niv_courant garde en mémoire le niveau courant
	  if (courant == 20)
	    sortie << "\\subsection*{Magie universelle}" << endl;
	  else
	    sortie << "\\subsection*{" << affiche_accent(nom_ecoles[courant])
		   << "}" << endl;
	  sortie << "\\subsubsection*{Niveau " << niv_courant << "}" << endl;
	}
      if (Cl_sorts[i].get_Niveau() != niv_courant)
	{
	  niv_courant = Cl_sorts[i].get_Niveau();
	  sortie << "\\subsubsection*{Niveau " << niv_courant << "}" << endl;
	}
      if (courant == 20)
      sortie << "\\input{../../Sorts-mage/Universelle" << "/sort_"
	     << niv_courant << "_" << Cl_sorts[i].get_Numero() << ".inc.tex}"
	     << endl;
      else
	sortie << "\\input{../../Sorts-mage/"
	       << supprime_accents(nom_ecoles[courant]) << "/sort_"
	       << niv_courant << "_" << Cl_sorts[i].get_Numero()
	       << ".inc.tex}" << endl;
    }

  sortie.close();
  dout(FUNC) << "Mage::ecrire_sorts -> fin" << endreq;
  dout.setLevel(etat_precedent);
}

void Mage::nbr_sort(unsigned int sorts[], const unsigned int& taille) const
{
  DebugLevelType etat_precedent(dout.getLevel());
  dout.setLevel(fonction);
  dout(FUNC) << "Mage::nbr_sort -> début" << endreq;
  unsigned int i;
  unsigned int tmp[7];
  dout(FUNC) << "Niveau de magie = " << taille << endreq;

  for (i = 0; i < taille; i++)
    tmp[i] = 0;

  switch(Niveau)
    {
    case 1:
      tmp[0] = 1;
      break;
    case 2:
      tmp[0] = 2;
      break;
    case 3:
      tmp[0] = 2;
      tmp[1] = 1;
      break;
    case 4:
      tmp[0] = 3;
      tmp[1] = 2;
      break;
    case 5:
      tmp[0] = 4;
      tmp[1] = 2;
      tmp[2] = 1;
      break;
    case 6:
      tmp[0] = 4;
      tmp[1] = 2;
      tmp[2] = 2;
      break;
    case 7:
      tmp[0] = 4;
      tmp[1] = 3;
      tmp[2] = 2;
      tmp[3] = 1;
      break;
    case 8:
      tmp[0] = 4;
      tmp[1] = 3;
      tmp[2] = 3;
      tmp[3] = 2;
      break;
    case 9:
      tmp[0] = 4;
      tmp[1] = 3;
      tmp[2] = 3;
      tmp[3] = 2;
      tmp[4] = 1;
      break;
    case 10:
      tmp[0] = 4;
      tmp[1] = 4;
      tmp[2] = 3;
      tmp[3] = 2;
      tmp[4] = 2;
      break;
    case 11:
      tmp[0] = 4;
      tmp[1] = 4;
      tmp[2] = 4;
      tmp[3] = 3;
      tmp[4] = 3;
      break;
    case 12:
      tmp[0] = 4;
      tmp[1] = 4;
      tmp[2] = 4;
      tmp[3] = 4;
      tmp[4] = 4;
      tmp[5] = 1;
      break;
    case 13:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 4;
      tmp[4] = 4;
      tmp[5] = 2;
      break;
    case 14:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 4;
      tmp[4] = 4;
      tmp[5] = 2;
      tmp[6] = 1;
      break;
    case 15:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 5;
      tmp[4] = 5;
      tmp[5] = 2;
      tmp[6] = 1;
      break;
    case 16:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 5;
      tmp[4] = 5;
      tmp[5] = 3;
      tmp[6] = 2;
      tmp[7] = 1;
      break;
    case 17:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 5;
      tmp[4] = 5;
      tmp[5] = 3;
      tmp[6] = 3;
      tmp[7] = 2;
      break;
    case 18:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 5;
      tmp[4] = 5;
      tmp[5] = 3;
      tmp[6] = 3;
      tmp[7] = 2;
      tmp[8] = 1;
      break;
    case 19:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 5;
      tmp[4] = 5;
      tmp[5] = 3;
      tmp[6] = 3;
      tmp[7] = 3;
      tmp[8] = 1;
      break;
    default:
      tmp[0] = 5;
      tmp[1] = 5;
      tmp[2] = 5;
      tmp[3] = 5;
      tmp[4] = 5;
      tmp[5] = 4;
      tmp[6] = 3;
      tmp[7] = 3;
      tmp[8] = 2;
      break;
    }

  for (i = 0; i < Niveau_mag; i++)
    sorts[i] = tmp[i];

  dout(FUNC) << "Mage::nbr_sort -> fin" << endreq;
  dout.setLevel(etat_precedent);
}

/*****************************************************************************
 *
 * Permet de gérer l'ajout de sorts au livre du magicien
 *
 * FUNC  permet d'afficher les messages de début - fin de la méthode
 * LFUNC permet d'afficher les écoles auxquelles le Mage a accès
 *
 *****************************************************************************/
void Mage::ajout_sorts()
{
  DebugLevelType etat_precedent(dout.getLevel());
  dout.setLevel(fonction);
  dout(FUNC) << "Mage::ajout_sorts -> début" << endreq;

  bool ecoles[9] = {false, false, false, false, false, false, false, false};
  unsigned int taille(get_combien()), i;

  for (i = 0; i < taille; i++)
    {
      if (Comp_classe[i] < 8)
	{
	  ecoles[Comp_classe[i]] = true;
	  dout(LFUNC) << get_competence(i) << " oui" << endreq;
	}
    }

  unsigned int nbr, dernier;
  string ecole;

  // On ajoute l'école de magie universelle
  dout(BLANK) << "Magie universelle" << endreq;
  for (i = 1; i <= Niveau_mag; i++)
    {
      dout(BLANK) << "Niveau " << i << " :" << endreq;
      dernier = affiche_sorts(20, i);

      dout(DEBUG) << "dernier = " << dernier << endreq;

      if (dernier > 0)
	{
	  dout(BLANK) << setw(2) << dernier + 1 << " Aucun" << endreq;
	  do
	    {
	      nbr = demander_unsigned_borne("Entrer nouveau sort : ", 1,
					    dernier + 1);
	      if (nbr != dernier + 1)
		{
		  dout(DEBUG) << "Ajout du sort " << Sort(20, i, nbr - 1)
			      << endreq;
		  Cl_sorts.push_back(Sort(20, i, nbr - 1));
		}
	    }
	  while(nbr != dernier + 1);
	}
    }

  for (i = 0; i < 8; i++)
    {
      if (!ecoles[i])
	continue;
      dout(BLANK) << get_competence(i) << endreq;
      for (unsigned int j(1); j <= Niveau_mag; j++)
	{
	  dout(BLANK) << "Niveau " << j << " :" << endreq;
	  dernier = affiche_sorts(i, j);

	  dout(DEBUG) << "dernier = " << dernier << endreq;
	
	  if (dernier > 0)
	    {
	      dout(BLANK) << setw(2) << dernier + 1 << " Aucun" << endreq;
	      do
		{
		  nbr = demander_unsigned_borne("Entrer nouveau sort : ", 1,
						dernier + 1);
		  if (nbr != dernier + 1)
		    {
		      dout(DEBUG) << "Ajout du sort " << Sort(i, j, nbr - 1)
				  << endreq;
		      Cl_sorts.push_back(Sort(i, j, nbr - 1));
		    }
		}
	      while(nbr != dernier + 1);
	    }
	}
    }

  vector<Sort>::iterator Begin, End, it;
  Begin = Cl_sorts.begin();
  End   = Cl_sorts.end();

  for (i = 0; i < Cl_sorts.size(); i++)
    dout(DEBUG) << Cl_sorts[i] << endreq;

  dout(DEBUG) << "Tri effectué" << endreq;

  sort(Begin, End);

  for (it = ++Begin; it != End; it++)
    {
      if (*it == *(it - 1))
	{
	  dout(LFUNC) << "Même sort!" << endreq;
	  Cl_sorts.erase(it);
	}
    }

  for (i = 0; i < Cl_sorts.size(); i++)
    dout(DEBUG) << Cl_sorts[i] << endreq;

  dout(FUNC) << "Mage::ajout_sorts -> fin" << endreq;
  dout.setLevel(etat_precedent);
}
